/*
 * Copyright (C) 2025 Tsingteng MicroSystem
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#ifndef _NCI_UTILS_H_
#define _NCI_UTILS_H_

#include "nci_transport.h"

/**
 * @file nci_utils.h
 * @brief NCI工具函数
*/

/**
 * @brief 确认NCI BUF容量是否足够
 *
 * @note 如果NCI BUF容量不够，则会进行扩容
 *
 * @param buf 待确认的NCI BUF
 * @param increased 需要插入的数据长度
*/
#define CONFIRM_BUF_CAP(buf, increased) \
    if ((buf)->cap < ((buf)->len + increased)) { \
        realloc_nci_buf(buf, (buf)->len + increased); \
    }

/**
 * @brief 插入一个uint8_t到NCI BUF
 *
 * @param buf 被插入的NCI BUF
 * @param u8 待插入的uint8_t
*/
#define UINT8_TO_BUF(buf, u8) \
    { \
        CONFIRM_BUF_CAP(buf, 1); \
        (buf)->data[(buf)->len++] = (uint8_t) (u8); \
    }

/**
 * @brief 以小端模式插入一个uint16_t到NCI BUF
 *
 * @param buf 被插入的NCI BUF
 * @param u16 待插入的uint16_t
*/
#define UINT16_TO_BUF_LE(buf, u16) \
    { \
        CONFIRM_BUF_CAP(buf, 2); \
        (buf)->data[(buf)->len++] = (uint8_t) (u16); \
        (buf)->data[(buf)->len++] = (uint8_t) ((u16) >> 8); \
    }

/**
 * @brief 以大端模式插入一个uint16_t到NCI BUF
 *
 * @param buf 被插入的NCI BUF
 * @param u16 待插入的uint16_t
*/
#define UINT16_TO_BUF_BE(buf, u16) \
    { \
        CONFIRM_BUF_CAP(buf, 2); \
        (buf)->data[(buf)->len++] = (uint8_t) ((u16) >> 8); \
        (buf)->data[(buf)->len++] = (uint8_t) (u16); \
    }
/**
 * @brief 以小端模式插入一个uint32_t到NCI BUF
 *
 * @param buf 被插入的NCI BUF
 * @param u32 待插入的uint32_t
*/
#define UINT32_TO_BUF_LE(buf, u32) \
    { \
        CONFIRM_BUF_CAP(buf, 4); \
        (buf)->data[(buf)->len++] = (uint8_t) (u32); \
        (buf)->data[(buf)->len++] = (uint8_t) ((u32) >> 8); \
        (buf)->data[(buf)->len++] = (uint8_t) ((u32) >> 16); \
        (buf)->data[(buf)->len++] = (uint8_t) ((u32) >> 24); \
    }

/**
 * @brief 以大端模式插入一个uint32_t到NCI BUF
 *
 * @param buf 被插入的NCI BUF
 * @param u32 待插入的uint32_t
*/
#define UINT32_TO_BUF_BE(buf, u32) \
    { \
        CONFIRM_BUF_CAP(buf, 4); \
        (buf)->data[(buf)->len++] = (uint8_t) ((u32) >> 24); \
        (buf)->data[(buf)->len++] = (uint8_t) ((u32) >> 16); \
        (buf)->data[(buf)->len++] = (uint8_t) ((u32) >> 8); \
        (buf)->data[(buf)->len++] = (uint8_t) (u32); \
    }

/**
 * @brief 将uint8_t数组插入NCI BUF
 *
 * @param buf 待插入的NCI BUF
 * @param p 待插入的uint8_t数组
 * @param length 待插入的uint8_t数组长度
*/
#define ARRAY_TO_BUF(buf, p, length) \
    { \
        CONFIRM_BUF_CAP(buf, length); \
        int _i = 0; \
        for (_i = 0; _i < (length); _i++) { \
            (buf)->data[(buf)->len++] = (uint8_t) ((p)[_i]); \
        } \
    }
/**
 * @brief 向NCI BUF中填充指定长度数据
 *
 * @param buf 待填充的NCI BUF
 * @param val 填充的值
 * @param len 填充的长度
 */
#define FILL_BUF(buf, val, length)                   \
  {                                                  \
    CONFIRM_BUF_CAP(buf, length);                    \
    int _i = 0;                                      \
    for (_i = 0; _i < (length); _i++) {              \
      (buf)->data[(buf)->len++] = (uint8_t) (val);   \
    }                                                \
  }
/**
 * @brief 向STREAM中插入一个uint8_t，并移动指针到下一个位置
 * @param p 待插入的uint8_t数组
 * @param u8 待插入的uint8_t
 */
#define UINT8_TO_STREAM(p, u8) \
  { *(p)++ = (uint8_t)(u8); }
/**
 * @brief 向STREAM中以大端格式插入一个uint16_t，并移动指针到下一个位置
 * @param p 待插入的uint8_t数组
 * @param u16 待插入的uint16_t
 */
#define UINT16_TO_STREAM_BE(p, u16) \
  {                                 \
    *(p)++ = (uint8_t)((u16) >> 8); \
    *(p)++ = (uint8_t)(u16);        \
  }
/**
 * @brief 向STREAM中以小端格式插入一个uint16_t，并移动指针到下一个位置
 * @param p 待插入的uint8_t数组
 * @param u16 待插入的uint16_t
 */
#define UINT16_TO_STREAM_LE(p, u16) \
  {                                 \
    *(p)++ = (uint8_t)(u16);        \
    *(p)++ = (uint8_t)((u16) >> 8); \
  }
/**
 * @brief 向STREAM中以大端格式插入一个uint24_t，并移动指针到下一个位置
 * @param p 待插入的uint8_t数组
 * @param u24 待插入的uint24_t
 */
#define UINT24_TO_STREAM_BE(p, u24)  \
  {                                  \
    *(p)++ = (uint8_t)((u24) >> 16); \
    *(p)++ = (uint8_t)((u24) >> 8);  \
    *(p)++ = (uint8_t)(u24);         \
  }
/**
 * @brief 向STREAM中以小端格式插入一个uint24_t，并移动指针到下一个位置
 * @param p 待插入的uint8_t数组
 * @param u24 待插入的uint24_t
 */
#define UINT24_TO_STREAM_LE(p, u24)  \
  {                                  \
    *(p)++ = (uint8_t)(u24);         \
    *(p)++ = (uint8_t)((u24) >> 8);  \
    *(p)++ = (uint8_t)((u24) >> 16); \
  }
/**
 * @brief 向STREAM中以大端格式插入一个uint32_t，并移动指针到下一个位置
 * @param p 待插入的uint8_t数组
 * @param u32 待插入的uint32_t
 */
#define UINT32_TO_STREAM_BE(p, u32)  \
  {                                  \
    *(p)++ = (uint8_t)((u32) >> 24); \
    *(p)++ = (uint8_t)((u32) >> 16); \
    *(p)++ = (uint8_t)((u32) >> 8);  \
    *(p)++ = (uint8_t)(u32);         \
  }
/**
 * @brief 向STREAM中以小端格式插入一个uint32_t，并移动指针到下一个位置
 * @param p 待插入的uint8_t数组
 * @param u32 待插入的uint32_t
 */
#define UINT32_TO_STREAM_LE(p, u32)  \
  {                                  \
    *(p)++ = (uint8_t)(u32);         \
    *(p)++ = (uint8_t)((u32) >> 8);  \
    *(p)++ = (uint8_t)((u32) >> 16); \
    *(p)++ = (uint8_t)((u32) >> 24); \
  }
/**
 * @brief 向STREAM中以大端格式插入一个uint8_t数组
 * @param p 待插入的uint8_t数组
 * @param a 被插入的uint8_t数组
 * @param len 插入的长度
 */
#define ARRAY_TO_STREAM_BE(p, a, len)                         \
  {                                                           \
    int _i;                                                   \
    for (_i = 0; _i < (len); _i++) *(p)++ = (uint8_t)(a)[_i]; \
  }
/**
 * @brief 向STREAM中填充指定长度数据,并移动指针到下一个位置
 *
 * @param buf 待填充的uint8_t数组
 * @param val 填充的值
 * @param len 填充的长度
 */
#define FILL_STREAM(p, val, length)                \
  {                                                \
    int _i;                                        \
    for (_i = 0; _i < (len); _i++) *(p)++ = (val); \
  }

/**
 * @brief 从uint8_t字节流中读取一个uint8_t，并且将指针指向下一个字节
 *
 * @param u8 用于保存读取的uint8_t
 * @param p 指向uint8_t字节流的指针
*/
#define STREAM_TO_UINT8(u8, p) \
    {                            \
        (u8) = (uint8_t)(*(p));    \
        (p) += 1;                  \
    }

/**
 * @brief 从uint8_t字节流中按小端读取一个uint16_t，并且将指针指向下一个字节
 *
 * @param u16 用于保存读取的uint16_t
 * @param p 指向uint8_t字节流的指针
*/
#define STREAM_TO_UINT16_LE(u16, p)                                   \
    {                                                                 \
        (u16) = ((uint16_t)(*(p)) + (((uint16_t)(*((p) + 1))) << 8)); \
        (p) += 2;                                                     \
    }

/**
 * @brief 从uint8_t字节流中按大端读取一个uint16_t，并且将指针指向下一个字节
 *
 * @param u16 用于保存读取的uint16_t
 * @param p 指向uint8_t字节流的指针
*/
#define STREAM_TO_UINT16_BE(u16, p)                                   \
    {                                                                 \
        (u16) = ((uint16_t)((*(p)) << 8) + ((uint16_t)(*((p) + 1)))); \
        (p) += 2;                                                     \
    }

/**
 * @brief 从uint8_t字节流中按小端读取一个uint32_t，并且将指针指向下一个字节
 *
 * @param u32 用于保存读取的uint32_t
 * @param p 指向uint8_t字节流的指针
*/
#define STREAM_TO_UINT32_LE(u32, p)                                       \
    {                                                                     \
        (u32) = (((uint32_t)(*(p))) + ((((uint32_t)(*((p) + 1)))) << 8) + \
                ((((uint32_t)(*((p) + 2)))) << 16) +                      \
                ((((uint32_t)(*((p) + 3)))) << 24));                      \
        (p) += 4;                                                         \
    }

/**
 * @brief 从uint8_t字节流中按大端读取一个uint32_t，并且将指针指向下一个字节
 *
 * @param u32 用于保存读取的uint32_t
 * @param p 指向uint8_t字节流的指针
*/
#define STREAM_TO_UINT32_BE(u32, p)                                                \
    {                                                                              \
        (u32) = (((uint32_t)((*(p))) << 24) + ((((uint32_t)(*((p) + 1)))) << 16) + \
                ((((uint32_t)(*((p) + 2)))) << 8) +                                \
                ((((uint32_t)(*((p) + 3)))) << 0));                                \
        (p) += 4;                                                                  \
    }

/**
 * @brief 从uint8t字节流中读取一个uint8_t数组(长度8),并且将指针指向下一个字节
 *
 * @param a 用于保存读取的uint8_t数组
 * @param p 指向uint8_t字节流的指针
*/
#define STREAM_TO_ARRAY8(a, p)                     \
    {                                                \
        int ijk;                                       \
        uint8_t* _pa = (uint8_t*)(a) + 7;              \
        for (ijk = 0; ijk < 8; ijk++) *_pa-- = *(p)++; \
    }

/**
 * @brief 从uint8t字节流中读取一个uint8_t数组,并且将指针指向下一个字节
 *
 * @param a 用于保存读取的uint8_t数组
 * @param p 指向uint8_t字节流的指针
 * @param len 读取的长度
*/
#define STREAM_TO_ARRAY(a, p, len)                                   \
    {                                                                  \
        int ijk;                                                         \
        for (ijk = 0; ijk < (len); ijk++) ((uint8_t*)(a))[ijk] = *(p)++; \
    }

/**
 * @brief 交换两个NCI_BUF的内容
 *
 * @note 交换后两个NCI_BUF指针不变，但是指向的内容会交换
 *
 * @param buf1 NCI_BUF结构体指针
 * @param buf2 NCI_BUF结构体指针
*/
#define SWAP_NCI_BUF(buf1, buf2) \
    { \
        tNCI_BUF _temp = {0}; \
        osi_memcpy_s(&_temp, sizeof(tNCI_BUF), buf1, sizeof(tNCI_BUF)); \
        osi_memcpy_s(buf1, sizeof(tNCI_BUF), buf2, sizeof(tNCI_BUF)); \
        osi_memcpy_s(buf2, sizeof(tNCI_BUF), &_temp, sizeof(tNCI_BUF)); \
    }

/**
 * @brief 分配一个NCI_BUF结构体
 *
 * @param head NCI指令头
 * @return tNCI_BUF* 返回一个tNCI_BUF结构体指针
*/
tNCI_BUF *alloc_nci_buf(uint16_t head);
/**
 * @brief 分配一个NCI_BUF结构体, 可以指定容量
 *
 * @param head NCI指令头
 * @param cap 容量
 * @return tNCI_BUF* 返回一个tNCI_BUF结构体指针
*/
tNCI_BUF* alloc_nci_buf_with_cap(uint16_t head, uint16_t cap);
/**
 * @brief 释放一个NCI_BUF结构体
 *
 * @note 释放NCI_BUF结构体时，同时也会释放其内部的raw数据
 * @note buf为NULL时，不做任何操作
 *
 * @param buf NCI_BUF结构体指针
*/
void free_nci_buf(tNCI_BUF *buf);

/**
 * @brief 清空NCI_BUF中保存的数据
 *
 * @param buf NCI_BUF结构体指针
*/
void reset_nci_buf(tNCI_BUF *buf);

/**
 * @brief 重新分配NCI_BUF的容量，已保存的数据会拷贝保留
 *
 * @note 扩容后tNCI_BUF指针不变
 *
 * @param buf NCI_BUF结构体指针
 * @param new_cap 新容量，不能和现有容量相同，且必须大于已保存数据的长度
*/
bool realloc_nci_buf(tNCI_BUF *buf, uint16_t new_cap);

#endif /* _NCI_UTILS_H_ */
